function log(msg) {
    const DEBUG = false
    if (DEBUG) {
        console.log(msg)
    }
}

function resize_bg() {
    let width = window.innerWidth
    let height = window.innerHeight;
    let ele = document.getElementById("image");
    let size = height < width ? width : height
    let size_extend = 1.1 * size
    let height_offset = height < width ? (width - height) / 2 : 0
    let width_offset = width < height ? (height - width) / 2 : 0;

    ele.style.width = size_extend + "px"
    ele.style.height = size_extend + "px"
    ele.style.marginLeft = .05 * -size - width_offset + "px"
    ele.style.marginTop = .05 * -size - height_offset + "px"
    ele.style.backgroundSize = size_extend + "px " + size_extend + "px"
}

window.onresize = function () {
    resize_bg()
};

// Audio object
const player = new Audio();
player.autoplay = true

// mTitle
const mTitle = new MTitle(document.title);

// auto play after switch song
let auto_play = false
// cookies timeout
const cookie_timeout = 30
// fall back audio
const fall_back = 'assets/audio/FAIL.mp3'
// vue
const app = new Vue({
    el: '#eraser_music',
    data: {
        version: {
            player: '1.4.2'
        },
        ready: false,
        visits: 0,
        valid_time: 0,
        counter: '00:00',
        uid: '欢迎使用橡皮音乐',
        menu: {
            a: 'inactive',
            b: 'inactive',
            c: 'active'
        },
        volume: 100,
        keyword: '',
        searching: {},
        pending: false,
        search_param: {
            hot: [],
            history: []
        },
        history: [],
        list: [],
        wipe_time: {
            history_search: 0,
            history_play: 0
        },
        present: {
            album: 'https://cdn.lifanko.cn/img/nocover.jpg',
            past: '-:--',
            left: '-:--',
            total: 0,
            status: 'loading',
            counter: 0,
            seeking: false
        },
        LYRIC: {},
        auto_next_timer: null
    },
    methods: {
        init: function () {
            console.log("%c2021 ©lifankohome EraserMusic-v" + app.version.player + " OpenSource: https://gitee.com/lifanko/eraser-music", "color:#D50;background-color:#ddd;padding:5px;border-radius:2px;")

            // set and save uid in cookies
            let uid = getCookie('eraser_music');
            if (uid === null) {
                uid = getRandomString(24);
                setCookie("eraser_music", uid, cookie_timeout);
            }
            app.ready = true
            app.uid = uid
            // set and save volume in cookies
            let volume = getCookie('eraser_music-volume');
            if (volume === null) {
                volume = 100;
                setCookie("eraser_music-volume", volume, cookie_timeout);
            }
            app.volume = volume
            // update volume display
            this.set_volume()
            // get params from backend
            $.get("api.php", {
                o: 'init',
                u: uid
            }, function (res) {
                // adjust background
                resize_bg()

                if (res.substr(0, 5) === '<?php') {
                    app.err()
                    return;
                }

                res = eval("(" + res + ")")
                if (app.check(res) === false) {
                    return;
                }

                // Version & Cnt
                app.version.backend = res.data.version.backend
                app.version.Meting = res.data.version.Meting
                app.visits = res.data.visits
                app.valid_time = res.data.valid_time

                app.history = res.data.history
                if (res.data.list.length && res.data.list[0].url === 'FAIL') {
                    res.data.list[0].url = fall_back
                }
                app.list = res.data.list
                app.search_param = res.data.search_param
                // TODO optimise: remove or jump out
                app.searching = res.data.search_param.platform
                for (let key in app.searching) {
                    if (app.searching.hasOwnProperty(key)) {
                        app.searching = {
                            platform: key,
                            msg: ''
                        }
                    }
                    break;
                }
                // register player callback
                init_player()
                // player load first song in list, no auto play
                set_present(0)

                // adjust background
                resize_bg()

                setTimeout(function () {
                    document.getElementById("image").classList.add('bg_animation')
                }, 50)
            }).fail(function () {
                app.err()
            });
        },
        err: function () {
            console.log('Backend interface (data) error, search target not found.')

            app.sw_menu('a')
        },
        sw_menu: function (index) {
            // switch menu by index
            if (app.menu[index] === 'active') {
                return;
            }
            app.menu = {
                a: 'inactive',
                b: 'inactive',
                c: 'inactive'
            }
            app.menu[index] = 'active'
        },
        play: function () {
            // auto play&pause according player status
            let status = app.present.status
            if (status === 'ready' || status === 'pause') {
                player.play()
            } else {
                player.pause()
            }
        },
        check_next: function () {
            // if error happened, [auto-next] will be trigger in 3s,
            // if user click next or select another song during this time, cancel [auto-next]
            if (app.auto_next_timer !== null) {
                tip("自动切换已取消", "50%", 2000, "1", true);
                clearTimeout(app.auto_next_timer)
                app.auto_next_timer = null
                log('auto-next timer canceled')
            }
        },
        prev: function () {
            // previous song

            app.check_next()

            // set status to pause
            app.present.status = 'pause'
            // auto play after select next song
            auto_play = true

            // get present index
            let index = present_index()
            // jump to previous or return to list bottom
            if (index === 0) {
                index = app.list.length - 1
            } else {
                index -= 1
            }
            // start loading this song
            this.confirm(index)
        },
        next: function (e) {
            // next song

            if (e === 'error') {
                log('auto-next execute')
                app.auto_next_timer = null
            } else {
                app.check_next()
            }

            // set status to pause
            app.present.status = 'pause'
            // auto play after select next song
            auto_play = true
            // get present index
            let index = present_index()
            log('index: ' + index)
            // jump to next or return to list top
            if (index === app.list.length - 1) {
                index = 0
            } else {
                index++
            }
            // start loading this song
            this.confirm(index)
        },
        select: function (id) {
            // select song while click a song

            app.check_next()

            // auto_play make song play automatic after selected complete
            auto_play = true
            if (id === app.present.id) {
                // if song has been selected, perform play and pause
                this.play()
                return;
            }
            // get list index by music id
            let index = present_index(id)
            // start loading this song
            this.confirm(index)
        },
        add: function (index) {
            // add song from history

            // get insert item
            let item = app.history[index]
            // if list exist this song, play this and not add
            if (app.present.id !== undefined && item.id !== undefined) {
                let exist = app.list.every(item_list => {
                    if (item_list.id === item.id) {
                        // play this song exist in list
                        this.select(item.id)

                        return false
                    }
                    log(item.id)
                    return true
                })
                if (exist === false) {
                    // stop add song to list
                    log('exist')
                    return;
                }
            }
            // get present list's index
            let idx = present_index() + 1
            // add song after present song: index+1 (present song is NG cause add this song)
            app.list.splice(idx, 0, item)
            // play this song
            this.confirm(idx)
        },
        confirm: function (index) {
            // select song by index of list

            // parsing start, show tip on the right of the list head
            app.pending = true
            // pause player after change song
            player.pause()
            // player controller status
            app.present.status = 'loading'

            let now = new Date() / 1000

            // check if url has been parsed
            if (app.list[index].url === fall_back) {
                tip("音频解析失败，已停止播放", "50%", 3000, "1", true);
                // load data but don't play
                set_present(index, false)
            } else if (app.list[index].url.toString().substr(0, 4) === 'http' && (app.list[index].load_at > now - app.valid_time)) {
                // parse success, play this item
                set_present(index)
                // add history
                app.history.push({
                    id: app.present.id,
                    name: app.present.name,
                    author: app.present.author,
                    album: app.present.album,
                    url: app.present.url,
                    lyric: app.present.lyric,
                    timestamp: '新增'
                })
            } else {
                // parse before, play directly

                // parse url,lyric (album has been loaded while searching, or album in the list can't show)
                log('pending')

                $.get("api.php", {
                    u: app.uid,
                    o: 'parse',
                    p: app.list[index].platform,
                    n: app.list[index].name,
                    t: app.list[index].author,
                    a: app.list[index].album,
                    r: app.list[index].url_id,
                    l: app.list[index].lyric_id,
                    s: app.list[index].id
                }, function (res) {
                    res = eval("(" + res + ")")
                    if (app.check(res) === false) {
                        return;
                    }

                    // jump over if song can't parse
                    if (res.data.url === 'FAIL') {
                        log('parse error: ' + index)
                        tip("音频解析失败，自动切换下一曲", "50%", 1000, "1", true);
                        // set fall back item
                        app.list[index].url = fall_back
                        app.list[index].lyric = false
                        // play this item
                        set_present(index)
                    } else {
                        // set list
                        app.list[index].url = res.data.url
                        app.list[index].lyric = res.data.lyric
                        app.list[index].load_at = res.data.load_at
                        // play this item
                        set_present(index)
                        // add history
                        if (app.history.length === 0 || app.history[app.history.length - 1].id !== app.present.id) {
                            app.history.push({
                                id: app.present.id,
                                name: app.present.name,
                                author: app.present.author,
                                album: app.present.album,
                                url: app.present.url,
                                lyric: app.present.lyric,
                                timestamp: '新增'
                            })
                        }
                    }
                })
            }
        },
        seek_start: function () {
            app.present.seeking = true
        },
        seek_end: function () {
            if (!player.paused) {
                auto_play = true
            }

            player.currentTime = app.present.counter

            app.present.seeking = false
        },
        set_volume: function () {
            // save volume in cookies (Range: 0-100)
            setCookie("eraser_music-volume", app.volume, cookie_timeout);
            // player volume accept range: 0-1
            player.volume = app.volume / 100
        },
        search: function (platform) {
            // trim keyword
            app.keyword = app.keyword.trim()
            if (app.keyword.length === 0) {
                // show tip if input error
                this.search_tip('请输入关键词后进行搜索', 1000)
                return;
            } else {
                this.search_tip('正在 ' + app.search_param.platform[platform] + ' 中搜索')
            }

            $.get("api.php", {
                u: app.uid,
                o: 'search',
                k: app.keyword,
                p: platform
            }, function (res) {
                // add history local directly
                app.search_param.history.unshift(app.keyword)
                // show search buttons
                app.searching.msg = ''
                // parse data
                res = eval("(" + res + ")")
                if (app.check(res) === false) {
                    return;
                }

                if (res.data.length > 0) {
                    app.list = res.data
                    // switch menu to list
                    app.menu = {
                        a: 'inactive',
                        c: 'active'
                    }
                    // always record platform while searching, to query song detail as param
                    app.searching.platform = platform
                    // play the first song of the list
                    app.select(app.list[0].id)
                } else {
                    tip("未搜索到相关音频", "50%", 3000, "1", true);
                }
            })
        },
        err_album: function (key = null, index = null) {
            // fill album that load error with default img
            if (key === null && index === null) {
                app.present.album = 'https://cdn.lifanko.cn/img/nocover.jpg'
            } else {
                app[key][index].album = 'https://cdn.lifanko.cn/img/nocover.jpg'
            }
        },
        set_keyword: function (keyword) {
            app.keyword = keyword
        },
        search_tip: function (msg, timeout = 0) {
            // show tip in search page with timeout
            app.searching.msg = msg

            if (timeout > 0) {
                setTimeout(function () {
                    app.searching.msg = ''
                }, timeout)
            }
        },
        download: function () {
            // open new window tab to download music
            window.open(app.present.url)
        },
        wipe: function (key) {
            const MAX = 3
            let timer = null

            // double click ele to perform wipe function less than 3s
            if (app.wipe_time[key] === 0) {
                app.wipe_time[key] = MAX
                timer = setInterval(function () {
                    if (--app.wipe_time[key] === 0) {
                        clearInterval(timer)
                        timer = null
                    }
                }, 1000)
            } else {
                log('wipe')
                // TODO optimise: clearInterval(timer), how to get the value of timer

                // clear local data
                if (key === 'history_search') {
                    app.search_param['history'] = []
                } else if (key === 'history_play') {
                    app.history = []
                }

                // clear backend data
                $.get("api.php", {
                    u: app.uid,
                    o: 'wipe',
                    k: key
                }, function () {
                    // ignore
                })
            }
        },
        check: function (res) {
            // error tip
            if (res.code !== 1) {
                tip('读取数据失败：' + res.msg, "50%", 3000, "1", true);
                return false;
            }
        }
    }
})
// initial eraser music
app.init();

// register callback
function init_player() {
    player.onplay = function () {
        log('playing')
        app.present.status = 'playing'

        // modify title
        mTitle.newTitle('正在播放《' + app.present.name + '》-' + app.present.author + '【橡皮音乐】');
        mTitle.start();
    }
    player.onpause = function () {
        log('pause')
        app.present.status = 'pause'

        mTitle.newTitle('已暂停：' + app.present.name + ' - ' + app.present.author + '【橡皮音乐】');
        mTitle.stop(true);
    }
    player.oncanplay = function () {
        log('ready')
        app.present.status = 'ready'
        // auto play
        if (auto_play) {
            auto_play = false

            player.play().then(function () {
                log('auto-playing')
                app.present.status = 'playing'
            }).catch(function (reason) {
                log('auto-playing failed: ' + reason)
                app.present.status = 'pause'
            });
        }
        // init lyric
        index_lyric(0)
    }
    player.onload = function () {
        log('loading')
        app.present.status = 'loading'
    }
    player.onloadeddata = function () {
        app.present.total = parseInt(player.duration.toFixed(0))
        app.present.past = '0:00'
        app.present.left = '-' + sec2time(app.present.total)
        app.present.counter = 0
    }
    player.onended = function () {
        app.next()
    }
    player.ontimeupdate = function () {
        if (app.present.total === 0) {
            // play error, block timeupdate
            return;
        }

        app.present.past = sec2time(player.currentTime)
        app.present.left = '-' + sec2time(app.present.total - player.currentTime)
        if (app.present.seeking === false) {
            app.present.counter = player.currentTime.toFixed(0)
        }

        // update lyric
        index_lyric(player.currentTime)
    }
    player.onerror = function () {
        // delete history that unable play
        app.history.pop()
        // show tip

        log('onerror')
        tip("音频加载失败，3秒后自动切换下一曲", "50%", 3000, "1", true);
        app.auto_next_timer = setTimeout(function () {
            app.next('error')
        }, 3000)
    }
}

// load LIST data of INDEX to PRESENT data & set player src so that start loading resource
function set_present(index, play = true) {
    if (app.list.length === 0) {
        return;
    }

    // parsing complete
    app.pending = false

    app.present.id = app.list[index].id
    app.present.name = app.list[index].name
    app.present.author = app.list[index].author
    app.present.album = app.list[index].album
    app.present.url = app.list[index].url

    // parse lyric
    app.present.lyric = parse_lyric(app.list[index].lyric)

    if (play) {
        player.src = app.present.url
        log('set: ' + index)
    } else {
        log('set: ' + index + ' block')
    }
}

function parse_lyric(lyric) {
    log('parse lyric')
    if (lyric === false) {
        app.LYRIC.resource = [{
            timestamp: 0,
            text: '歌词加载失败'
        }]
        return;
    }

    let lyric_group = Array.from(lyric.matchAll(/\[(\d{2}:\d{2}\.\d{2,3})\](.*)/g))
    if (lyric_group.length) {
        app.LYRIC = {
            lines: lyric_group.length,
            current: 0,
            timestamp: 0,
            style: '',
            resource: []
        }

        // long lyric split automatic™
        let time_interval = []
        let time_buffer = 0;
        lyric_group.forEach(function (value) {
            let timestamp = parseInt(value[1].substring(0, 2)) * 60 + parseFloat(value[1].substring(3, 5))
            time_interval.push(timestamp - time_buffer)

            time_buffer = timestamp
        })

        let lyric_time_interval_index = 0
        lyric_group.forEach(function (value) {
            let timestamp = parseInt(value[1].substring(0, 2)) * 60 + parseFloat(value[1].substring(3, 5))
            let lyric = value[2]
            lyric_time_interval_index++;

            if (lyric.length > 25) {
                let split_lyric = lyric.split(' ')
                if (split_lyric.length > 2) {
                    // split long lyric
                    let i = 0
                    split_lyric.forEach(function (value) {
                        app.LYRIC.resource.push({
                            timestamp: timestamp + ((time_interval[lyric_time_interval_index] / (split_lyric.length + 1)) * i),
                            text: value
                        })
                        i++;
                    })
                    app.LYRIC.resource.push({
                        timestamp: timestamp + time_interval[lyric_time_interval_index],
                        text: '橡皮音乐自动分句已应用'
                    })
                    return;
                }
            }
            app.LYRIC.resource.push({
                timestamp: timestamp,
                text: lyric
            })
        })
    } else {
        lyric_group = Array.from(lyric.matchAll(/(.*)\n/g))
        if (lyric_group.length) {
            app.LYRIC = {
                lines: lyric_group.length,
                current: 0,
                timestamp: 0,
                style: '',
                resource: []
            }
            lyric_group.forEach(function (value) {
                app.LYRIC.resource.push({
                    timestamp: 0,
                    text: value[1]
                })
            })
        }
    }
}

// set lyric focus by timestamp
function index_lyric(timestamp) {
    if (app.LYRIC.lines === 0 || app.present.total === 0) {
        log('index lyric block')
        return;
    }
    // reset only when timestamp bigger than present
    if (timestamp >= app.LYRIC.timestamp) {
        // cancel last active line
        if (app.LYRIC.current >= 1) {
            app.LYRIC.resource[app.LYRIC.current - 1].active = false
        }
        // set active line
        app.LYRIC.resource[app.LYRIC.current].active = true
        // update next info
        if (app.LYRIC.current < app.LYRIC.lines - 1) {
            app.LYRIC.current++;
            app.LYRIC.timestamp = app.LYRIC.resource[app.LYRIC.current].timestamp
        }

        let current = app.LYRIC.current
        let offset = current < 10 ? 0 : current - 10
        // if auto-scroll
        //app.LYRIC.style = 'top: -' + (offset * 1.5) + 'rem;margin-bottom: -' + (offset * 1.5) + 'rem'
    }
}

// get the index of list base on music-id
function present_index(id = null) {
    if (id === null) {
        id = app.present.id
    }

    let list_index = false
    app.list.forEach((value, index) => {
        if (value.id === id) {
            list_index = index
            // TODO optimise: jump out
        }
    })
    return list_index
}

// convert second to player past&left time
function sec2time(seconds) {
    let sec = Math.floor(seconds % 60)
    if (sec < 10) {
        sec = '0' + sec
    }
    return Math.floor(seconds / 60) + ':' + sec
}

// set cookie with key and expire
function setCookie(cookieKey, cookieValue, expireDays) {
    let expDate = new Date();
    expDate.setDate(expDate.getDate() + expireDays);
    //noinspection JSDeprecatedSymbols
    document.cookie = cookieKey + "=" + escape(cookieValue) +
        ((expireDays == null) ? "" : "; expires=" + expDate.toGMTString());
}

// get cookie with key
function getCookie(cookieKey) {
    let arr, reg = new RegExp("(^| )" + cookieKey + "=([^;]*)(;|$)");
    //noinspection JSDeprecatedSymbols
    return (arr = document.cookie.match(reg)) ? unescape(arr[2]) : null;
}

// get string combine with random char
function getRandomString(len) {
    len = len || 32;
    let $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    let maxPos = $chars.length;
    let pwd = '';
    for (let i = 0; i < len; i++) {
        pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
    }
    return pwd;
}